iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0

這幾天調整完基本架構
再來繼續處理特殊規格元件的部分
有時候我們會在表單裡面看到一種列表
比如說新增聯絡人
會有一個Table呈現多筆資料
也許還會有新增修刪功能
今天就要來設計一下類似這樣的元件

設計上可能會參考之前組合元件的方式
用groupName把相關的欄位綁在一起
不過這邊我們會希望這個列表會有一個可控的formArray承接
這樣在設定檔裡面會多一個inputType="list"
當碰到這個型別的時候會產生formArray

// form-input.component.ts
if (setting.groupType == 'list' && !!setting.groupName)
{
    if (!this.innerForm.contains(setting.groupName))
    {
        let newFormArray = new FormArray([])
        this.innerForm.addControl(setting.groupName, newFormArray);
        this.pageSetting.form?.addControl(setting.groupName, newFormArray);
    }
    return
}

首先在讀取設定檔產生form的時候會多一段判斷是不是list的
這邊會在原本的邏輯之前 因為如果判斷跟list相關的欄位是連form都不會塞control的

getGroupList(group: FormGroup): string | any
    {

        let Result = Object.keys(group.value).map(obj =>
        {
            let innerControl = group.get(obj)
            if (innerControl?.value !== null && typeof innerControl?.value === 'object')
            {
                if (Array.isArray(innerControl.value))
                {
                    let fg = this.fb.group({});
                    fg.addControl(obj, innerControl);
                    return fg
                } else
                {
                    return innerControl
                }
            } else 
            {
                return obj;
            }
        });
        return Result;
    }

getGroupList這邊也有調整
我們這次的formArray會比較接近之前的組合元件
所以是走combo-field這一塊
這樣我們會需要傳分類完的fieldSettings以及在form裡面乘載相關的FormArray
但這邊如果直接傳FormArray的話 我們可能無法得知formArray的名稱
這樣後續要取fieldSettings的話會有點困難
所以我們這邊多包一層formGroup
這樣在取設定檔的時候可以透過object.keys去取得formArray的名稱

    getListSettings(formArrayName: string)
    {
        let listName = this.pageSetting.fieldSettings.find(f => f.name == formArrayName)?.groupName;
        return this.pageSetting.fieldSettings.filter(f => f.groupName == listName);
    }

這邊增加一個方法可以透過formArrayName取得相關的設定檔

// combo-field.component.html

  <div *ngIf="findFieldSetting('list')">
    <app-list [fieldSettings]="fieldSettings" [inputForm]="inputFormGroup">
    </app-list>
  </div>

這樣combo-field也不用太大變動
一樣新增list區塊

// list.component.ts
    @Input() fieldSettings!: FieldSetting[];
    @Input() inputForm!: any;
    innerFormArray!: FormArray;
    subFormGroup!: FormGroup;
    titleArr!: string[];

    get listKey()
    {
        return Object.keys(this.inputForm.value)[0]
    }

    get inputFormArray()
    {
        return this.inputForm.get(this.listKey) as FormArray
    }

    constructor(
        private fb: FormBuilder,
        private validatorService: ValidatorService
    ) { }

    ngOnInit(): void
    {
        this.titleArr = [];
        this.innerFormArray = new FormArray<FormGroup>([]);
        this.subFormGroup = new FormGroup({});
        let defaultValue!: string[];

        this.fieldSettings.forEach(setting =>
        {
            if (setting.inputType != 'list')
            {
                let newControl = this.fb.control(setting.defaultValue) as FormControl;

                if (setting.validator && setting.validator?.length > 0)
                {
                    if (!!setting.validator.find(v => v == 'required')) setting.required = true;
                    newControl.addValidators(this.validatorService.getValidators(setting.validator));
                }
                this.titleArr.push(setting.cname);
                this.subFormGroup.addControl(setting.name, newControl);
            } else
            {
                defaultValue = setting.defaultValue! as string[];
            }
        })
        defaultValue.forEach((value: any) =>
        {
            this.subFormGroup.reset();
            this.subFormGroup.patchValue(value);
            this.innerFormArray.push(this.subFormGroup);
        })
        this.inputFormArray.clear();

        this.innerFormArray.controls.forEach((group: AbstractControl) =>
        {
            this.inputFormArray.push(group);
        });
    }
// list.component.html
<table [formGroup]="inputForm">
  <thead>
    <tr>
      <th *ngFor="let title of titleArr">
        {{ title }}
      </th>
    </tr>
  </thead>
  <tbody formArrayName="{{ listKey }}">
    <tr
      *ngFor="let row of inputFormArray.controls; let i = index"
      [formGroupName]="i"
    >
      <td>
        <input formControlName="list-name" />
      </td>
      <td>
        <input formControlName="list-phone" />
      </td>
      <td>
        <input formControlName="list-mail" />
      </td>
    </tr>
  </tbody>
</table>

這邊我們會有個subFormGroup
透過設定檔我們會決定subFormGroup的內容
然後如果要新增 就會以subFormGroup為模板塞進innerFormArray裡面
這邊我們還沒有新增的機制
我們就加一段 如果list的設定檔裡面有defaultValue
那就按造defaultValue塞值到innerFormArray裡面
最後會再同步inputForm裡面的formArray

這次改的東西有點多
新增的部分我們明天繼續

今日程式:day24


上一篇
第23天 檢核管理
下一篇
第25天 列表編輯模式
系列文
簡單的事 最困難-Angular動態Form元件30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言